package com.bw.coupon.controller;

import redis.clients.jedis.Jedis;

/**
 * @Author：尚志豪
 * @Package：com.bw.coupon.controller
 * @Project：doudi-group-practical_training-02
 * @name：InventoryController
 * @Date：2025/1/21 18:02
 * 下单前库存校验优化  库存预热redis,防止雪崩,击穿,超卖
 */

public class InventoryController {


    private Jedis jedis;
    private static int productId = 1;



    public void init() {
        jedis = new Jedis("150.158.86.96", 6379);
    }


    // 防止缓存击穿
    // Redis 锁的 key
    private static final String LOCK_KEY = "lock:product:stock:" + productId;
    // 获取库存的方法
    public int getStock() {
        // 先从 Redis 缓存中获取库存
        String stock = jedis.get("product:stock:" + productId);
        if (stock != null) {
            return Integer.parseInt(stock);
        }
        // 如果 Redis 缓存为空，获取锁来防止缓存击穿
        if (acquireLock()) {
            try {
                // 再次检查库存，防止其他线程已经更新库存
                stock = jedis.get("product:stock:" + productId);
                if (stock != null) {
                    return Integer.parseInt(stock);
                }
                // 如果 Redis 缓存为空，则访问数据库
                int dbStock = queryStockFromDB();
                // 将数据库中的库存存入 Redis，并设置过期时间
                jedis.setex("product:stock:" + productId, 3600, String.valueOf(dbStock));
                return dbStock;
            } finally {
                releaseLock();  // 释放锁
            }
        }
        // 如果没有获取到锁，等待一段时间重试
        return getStock();
    }
    // 获取分布式锁
    private boolean acquireLock() {
        // 使用 SETNX 命令设置锁
        return jedis.setnx(LOCK_KEY, "locked") == 1;
    }
    // 释放锁
    private void releaseLock() {
        jedis.del(LOCK_KEY);
    }
    // 从数据库查询库存
    private int queryStockFromDB() {
        // 模拟数据库查询库存
        return 100;  // 假设库存为 100
    }

    //  使用 Lua 脚本防止超卖
    // Lua 脚本：减少库存
    private static final String LUA_DECREASE_STOCK_SCRIPT =
            "local stock = tonumber(redis.call('get', KEYS[1])) " +
                    "if stock and stock > 0 then " +
                    "redis.call('decr', KEYS[1]) " +
                    "return 1 " +
                    "else " +
                    "return 0 " +
                    "end";

    // 扣减库存
    public boolean decreaseStock() {
        // 执行 Lua 脚本来减少库存
        Object result = jedis.eval(LUA_DECREASE_STOCK_SCRIPT, 1, "product:stock:" + productId);
        return Integer.parseInt(result.toString()) == 1;
    }

}
